﻿import { sysLoginControllerLogin as toRefreshToken } from '@/services/login/sysLogin';
import { setTokenInfo } from '@/utils';
import type { RequestOptions } from '@@/plugin-request/request';
//import { CheckCircleOutlined } from '@ant-design/icons';
import { formatMessage } from '@/utils/globalIntl';
import type { RequestConfig as _RequestConfig } from '@umijs/max';
import { getLocale, history, request } from '@umijs/max';
import { message as messageModal, Modal, notification } from 'antd';
import qs from 'qs';

interface RequestConfig extends _RequestConfig {
  // 刷新token接口
  refreshTokenFetch?: boolean;
  // 跳过常规错误处理
  skipErrorHandler?: boolean;
}

const LOGIN_URL = '/user/login';

// 错误处理方案： 错误类型
enum ErrorShowType {
  NOTIFICATION = 3,
  REDIRECT = 9,

  PARAM_PARSING_ERROR = 400, //参数解析异常
  SYS_EXCEPETION = -1, // 系统异常
  NOT_LOGGED_IN = 23000, // 未登录
  LOGGED_IN_FAIL = 23001, // 被踢，重新登录
  LOGGED_IN_BANNED = 23002, // 主动退出登录
  PARAM_VERIFICATE_ERROR = 10004, //参数校验失败
  NO_ROLE = 10022, //角色未配置菜单
}

// 不自动弹出错误提示窗
const IGNORE_SHOW_MESSAGE_CODE = [10200, 10207, 10202, 10204];

// 与后端约定的响应数据格式
interface ResponseStructure {
  success: boolean;
  data: any;
  code: number;
  message: string;
}

interface PendingTask {
  config: RequestConfig;
  resolve: () => void;
}

let refreshing = false;
const queue: PendingTask[] = [];

function toLogin(msg) {
  messageModal.warning(msg ?? formatMessage('login.loginFail'));
  refreshing = false;
  history.push(LOGIN_URL);
}

type responseHandlerProps = (ResponseStructure) => ResponseStructure;

export const responseHandler: responseHandlerProps = async (response) => {
  const { config } = response;
  const { code, success, message } = (response?.data || {}) as unknown as ResponseStructure;

  // 忽略通用异常处理
  if (!config?.skipErrorHandler && !config.refreshTokenFetch && !success) {
    if (IGNORE_SHOW_MESSAGE_CODE.includes(code) || config?.ingoreErrorMsg) {
      return response;
    }

    switch (code) {
      case ErrorShowType.NO_ROLE:
        history.push('/');
        Modal.error({
          title: formatMessage('login.prompt'),
          content: message,
        });
        break;
      case ErrorShowType.NOTIFICATION:
        notification.open({
          description: message,
          message: code,
        });
        break;
      case ErrorShowType.REDIRECT:
        // TODO: redirect
        break;
      default:
        if (code && code !== 200) {
          messageModal.error(message || formatMessage('login.operateFail'));
        }
        break;
    }
  }

  return response;
};

const errorHandler = async (error: any) => {
  if (error.response) {
    if (error.response?.status === 401 || error.response?.status === 403) {
      const code = error.response?.data?.code;
      const msg = error.response?.data?.message;
      const config = error.response?.config;
      const refreshToken = localStorage.getItem('refreshToken') ?? '';
      const accessToken = localStorage.getItem('accessToken') ?? '';
      if (code === ErrorShowType.NOT_LOGGED_IN) {
        if (!config.refreshTokenFetch && refreshing) {
          return new Promise((resolve) => {
            queue.push({
              _config: config,
              _resolve: resolve,
            });
          });
        } else if (!config.refreshTokenFetch && !refreshing && accessToken && refreshToken) {
          refreshing = true;
          try {
            const res = await toRefreshToken(
              {
                refresh_token: refreshToken,
                grant_type: 'refresh_token',
              },
              {
                refreshTokenFetch: true,
              },
            );
            if (res.success) {
              setTokenInfo(res.data);
              refreshing = false;
              queue.forEach(({ _config, _resolve }) => {
                _resolve(
                  _config.downloadFun
                    ? _config.downloadFun()
                    : request(_config.url, { ..._config, getResponse: true }),
                );
              });
              return config.downloadFun
                ? config.downloadFun()
                : request(config.url, { ...config, getResponse: true });
            } else {
              toLogin();
            }
          } catch (error) {
            console.error(error);
            toLogin();
          }
        } else {
          toLogin();
        }
      } else if (code === ErrorShowType.LOGGED_IN_FAIL || code === ErrorShowType.LOGGED_IN_BANNED) {
        toLogin(msg);
      }
      //toLogin();
    } else if (error?.code === 'ERR_NETWORK' && error?.message === 'Network Error') {
      messageModal.error(formatMessage('login.errorNet'));
      return error.response;
    } else {
      // Axios 的错误
      // 请求成功发出且服务器也响应了状态码，但状态代码超出了 2xx 的范围
      messageModal.error(
        `${formatMessage('login.errorCode')}: ${error.response.status}，${error?.message}`,
      );
      return error.response;
    }
  } else if (error.request) {
    // 请求已经成功发起，但没有收到响应
    // \`error.request\` 在浏览器中是 XMLHttpRequest 的实例，
    // 而在node.js中是 http.ClientRequest 的实例
    messageModal.error(formatMessage('login.errorResponded'));
  } else {
    // 发送请求时出了点问题
    messageModal.error(formatMessage('login.errorRequest'));
  }
};

/**
 * @name 错误处理
 * pro 自带的错误处理， 可以在这里做自己的改动
 * @doc https://umijs.org/docs/max/request#配置
 */
export const errorConfig: RequestConfig = {
  paramsSerializer: (params) => {
    return qs.stringify(params, { encode: false });
  },

  // 请求拦截器
  requestInterceptors: [
    async (config: RequestOptions) => {
      // 拦截请求配置，进行个性化处理

      if (config.method === 'get' || config.url === '/auth/oauth2/token') {
        for (let i in config.params) {
          if (config.params[i]) {
            config.params[i] = encodeURIComponent(config.params[i]);
          }
        }
      }

      if (!/^\/api/.test(config?.url as string)) {
        config.url = '/api' + config?.url;
      }

      let locale = getLocale(); // 获取当前语言
      if (locale === 'zh-CN') {
        locale = 'zh_CN';
      } else {
        locale = 'en_US';
      }
      config.headers['Accept-Language'] = locale; // 设置 Accept-Language 头
      config.headers.Authorization = config.token ?? localStorage.getItem('accessToken') ?? '';
      config.headers['Station-Id'] = config?.stationId || sessionStorage.getItem('stationId') || '';

      return config;
    },
  ],

  // 响应拦截器
  responseInterceptors: [[responseHandler, errorHandler]],
};
